
import { FormationManager } from "GameLoop/Execution/FormationManager/FormationManager";
import { ATeamEntity, ETeamState } from "..";
import { PositionHelper } from "utils/position/PositionHelper";
import { cache_return } from "utils/decorate/decorate";
import { TeamUtils } from "utils/team/TeamUtils";
import { MoveTips } from "utils/constants/globalconstant";
import { Math2D } from "algorithm/Math2d";
import { angleIndex, movedirection } from "utils/war/warconstants";
import { TeamMoveUtils } from "utils/team/TeamMoveUtils";
import { attackRoles, combatRoles } from "utils/constants/bodyconstant";
import { DismantleStrategy } from "./utils/dismantleStrategy";
import { AttackStrategy } from "./utils/attackStrategy";
import { RangeAttackStrategy } from "./utils/rangeAttackStrategy";
import { avoidAnyMove } from "GameLoop/WorldState/mount/move/MoveExtension";
import { UtilsHelper } from "utils/position/UtilsHelper";
import { CreepAbilityHelper } from "utils/creep/CreepAbilityHelper";

/**
 * 战斗小队
 * 功能。1.检测过期的creep，将其移除。
 *       2.添加新的creep到合适的位置
 * 小队的生命周期。
 */
export abstract class ATeamCombat extends ATeamEntity<ITeamMemoryCombat,ITeamInitializer> implements ITeam ,ICombat<IAttackTactic>
{
    
    private _move_clonse_random_moveIndex:3|4=3;
    
    protected abstract  _Formation:FormationManager<Creep>;

    protected _aroundHostileCreeps:Creep[]=[];  // 周围的敌方单位

    _AssemblePos?:RoomPosition;     // 集合的队长坐标
    /***********************************************************
     * 抽象接口
     * 
     * 
    */
    protected initNodeMemory(): void {
        super.initNodeMemory();
        const memory = this.getNodeMemory();
        if(!memory.blockCreeps)
        {
            memory.blockCreeps=[]
        }
        if(memory.timeToLive === undefined)
        {
            memory.timeToLive=500
        }
    }
    /**
     * 获取可被攻击的爬
     */
    public abstract getAttackableCreeps():Creep[];
    // protected abstract  getHealer():Creep[];
    // protected abstract getAttacker():Creep[];
    /**
     * 是否在攻击范围之内
     * @param pos 
     * @param range 
     */
    public abstract isInCombatRange(pos:IRoomPosition,range?:number):boolean;
    public abstract isAssembleOver():boolean;// 是否集合完成
     
    public abstract moveByDirection(dir:DirectionConstant):boolean

    get teamTimeTickLive(): number {
        
        const mem = this.getNodeMemory()
        if(mem.teamState)
        {
            if(mem.teamState== ETeamState.Full)
            {
                // 满员
                return mem.timeToLive as number
            }
            // 减员 或者全灭
            return 0
        }
        else
        {
            if(mem.timeToLive === undefined)
            {
                // 从来没有过爬。表示正在孵化中
                return 1500
            }
            else 
            {   
                // 有过爬,则以当前还活着的爬的最小ttl为准
                return mem.timeToLive
            }
        }
    }
    public getTactic<T extends IAttackTactic=IAttackTactic>():T
    {
       return this.getNodeMemory().tactic as T
    }

    public setTactic<T extends IAttackTactic=IAttackTactic>(tatic:T):void
    {
        const memory = this.getNodeMemory();
        memory.goal = (tatic as IAttackTactic).goal ;
        memory.targets = tatic.targets.map(e=>{return {attackTarget:e}});
    }

    private updateAttackCache(memory:ITeamMemoryCombat)
    {
        if(!memory.targets|| !this.roomName)
        {
            return ;
        }
        
        if(memory.targets[0] && !UtilsHelper.isCenterRoom(this.roomName) && this.roomName == memory.targets[0].attackTarget.roomName)
        {
            if(memory.attack_cache)
            {
                if(!Game.rooms[this.roomName].IsFriend())
                {
                    for(let i=0;i<memory.attack_cache.length;i++)
                    {
                        const obj = Game.getObjectById(memory.attack_cache[i].attackTarget.id!);
                        if(!obj)
                        {
                            memory.attack_cache.splice(i,1);
                            i--;
                        }
                        else 
                        {
                            memory.attack_cache[i].attackTarget.x = obj.pos.x;
                            memory.attack_cache[i].attackTarget.y = obj.pos.y;
                        }
                    }
                    if(memory.attack_cache.length ==0)
                    {
                        memory.attack_cache=undefined;
                    }
                }
            }
            // 抵达目标房间
            if(!memory.attack_cache)
            {
                const nexttarget = this.getNextPositions();
                if(nexttarget)
                {
                    // 转火?
                    const attacktargets =_.flatten(nexttarget.map(e=>e.lookFor(LOOK_STRUCTURES).filter(e=>e.structureType !== STRUCTURE_ROAD && e.structureType !== STRUCTURE_CONTAINER && e.structureType !== STRUCTURE_CONTROLLER && e.structureType !== STRUCTURE_KEEPER_LAIR)));
                    if(attacktargets.length)
                    {
                        memory.attack_cache = attacktargets.map(e=>
                            {
                                return { attackTarget:PositionHelper.getObjectRef(e) }
                            }) as ITargetGroup[]
                    }
                }
            }
            
        };
    }
    public updateMemory(): void 
    {
        const memory = this.getNodeMemory();
        this.updateTeamState(memory);
        this.updateAttackCache(memory);
    }
    /**
     * 更新小队内存状态
     */
    private updateTeamState(memory:ITeamMemoryCombat): void 
    {
        // 更新小队状态
      
        {
            let sum=0;
            let except=0;
            let ttl=-1  ;
            for(const e of memory.required)
            {
                const team_member = memory.creeps[e[0].Role];
                const exist:string[]=[];
                if(team_member)
                {
                    team_member.forEach(c=>
                        {
                            const creep = Game.creeps[c];
                            if(creep  )
                            {
                                const creepttl = creep.ticksToLive?creep.ticksToLive:1500;
                                if(ttl<0)
                                {
                                    ttl =creepttl;
                                }else 
                                {
                                    ttl = Math.min(ttl,creepttl);
                                }
                                exist.push(c);
                            }
                        })
                }
                memory.creeps[e[0].Role] = exist;
                sum+=exist.length;
                except+= e[1];
            }
            if(ttl>=0)
            {
                // 只有当所有的爬都孵化完成之后才会设置
                // if(sum == except)
                {
                    memory.timeToLive = ttl;
                }                
            }
            else
            {
                if(memory.timeToLive!>500 && sum ==0)
                {
                    memory.timeToLive = 0
                }
                else 
                {
                    memory.timeToLive! --;
                }
                
            }
           
            if(memory.teamState)
            {
                // 初始化完成
                if(sum ==0 )
                {
                    // 全部狗带
                    memory.teamState = ETeamState.Dead;
                }
                else if(sum<except)
                {
                    // 减员了
                    memory.teamState = ETeamState.Absence;
                }
                else  if(sum>except)
                {
                    // 异常情况
                    this.log("warn","异常警告","实际持有的爬多余预期",sum,">",except)
                }
                else
                {
                    memory.teamState = ETeamState.Full;
                }
            }
            else
            {
                // 还在初始化
                if(sum == except)
                {
                    memory.teamState = ETeamState.Full;// 满员
                }
                else 
                {
                    // 这时候还在孵化中。
                    if(this.room.canExecute(100))
                    {
                        // 没有孵化任务,则表示孵化出现了bug
                        const task = this.room.getEntity('SpawnEntity').getTasksByOwner(this.GUID());
                        if(!task)
                        {
                            memory.teamState = ETeamState.Dead;
                        }
                    }
                }
                
            }
            if(memory.timeToLive===0)
            {
                // ttl 减为0都没有孵化
                memory.teamState = ETeamState.Dead;
            }
        }
        // this._Formation.update();
        // this.log('info',this.entityType(),"更新内存",this.creeps);
    }
    // 小队添加成员
    public addCreep(creeps: Creep[]) 
    {
        for(let creep of creeps)
        {
            if(this._Formation.addCharactor(creep))
            {
                creep.memory.teamid == this.GUID();
                if(!super.addCreep([creep]))
                {
                    this._Formation.removeCharactor(creep);
                    return false;
                }
            }
            else 
            {
                return false;
            }
        }
        return true;
    }

    public getHealer(): Creep[] {
        return this.creeps.filter(e=>!attackRoles.has(e?.ActiveRole()))
        // const memory = this.getNodeMemory();
        // if(memory.heal)
        // {
        //     return memory.heal.map(e=>Game.creeps[e])
        // }
        // return []
    }
    public getAttacker(): Creep[] {
        return this.creeps.filter(e=>attackRoles.has(e?.ActiveRole()))
        // const memory = this.getNodeMemory();
        // if(!memory.attack)
        // {
        //     return []
        // }
        // return memory.attack.map(e=>Game.creeps[e])
    }

    public get getAttackAbility():number
    {
        return _.sum(this.getAttacker(),e=>CreepAbilityHelper.getCreepAttackAbility( e));
    }
    /**
     * 设置周围的敌方单位
     * @param creeps 
     */
    public setAroundHostileCreeps(creeps:Creep[])
    {
        this._aroundHostileCreeps = creeps;
    }
    public pushAroundHostileCreep(creeps:Creep[])
    {
        this._aroundHostileCreeps.push(...creeps);
    }
    public findHostilesCreeps(): Creep[] 
    {
        return this._aroundHostileCreeps
    }
    /************************************************************************/
     /**
     * 注册当前阻挡寻路的位置
     * @param directions
     */
    public registerCurrentBlock()
    {
        const memory = this.getNodeMemory();
        const creepNames  =  _.flatten(Object.values(memory.creeps));

        for(const n of creepNames)
        {
            const creep =Game.creeps[n];
            if(creep )
            {
                creep.room.registerBlocks([creep.pos]);
            }
            else
            {
                this.log("error",n,"以及不存在但还没有从内存种删除掉")
            }
        }
    }
   

    // 队长位置
    public getAnchor(): RoomPosition {
        const memory = this.getNodeMemory();
        if(this.getAttacker()[0])
        {
            return this.getAttacker()[0]?.pos
        }
        return this.getHealer()[0]?.pos;
        // throw new Error("Method not implemented.");
    }
    // 中心点未知
    public center()
    {
        return this._Formation.Center()
    }
    /**
     * 当前队长所处于的房间
    */
    public get roomName()
    {
        return this.getAnchor()?.roomName
    }
    public get aroundHostileCreeps():Creep[]
    {
        return []
    }
    // 移动的目标位置
    public moveTarget()
    {
        const memory = this.getNodeMemory();
        if(memory.goal)
        {
            return memory.goal;
        }
        if(memory.attack_cache)
        {
            return {
                pos: PositionHelper.Create(memory.attack_cache[0].attackTarget),
                range:1
            } 
        }
        if(memory.targets && memory.targets[0])
        {
            
            return {
                pos: PositionHelper.Create(memory.targets[0].attackTarget),
                range:1
            } 
        }
        return undefined
    }

    // 寻路路径缓存
    public get path()
    {
        const memory = this.getNodeMemory();
        return memory.path;
    }
    // 小队成员里是否有疲劳大于0的
    public isFatigue()
    {
        const creeps = this.creeps;
        // const memory = this.getNodeMemory();
        for(const e of creeps)
        {
            if(e.fatigue)
            {
                return true;
            }
        }
        return false;
    }
    // 小队的朝向
    public getDirection(): IFVector2 {
        // throw new Error("Method not implemented.");
        const memory = this.getNodeMemory();
        const attacker = this.getAttacker()  ;
        const healer =  this.getHealer() ;
        let sum_x = 0;
        let sum_y = 0;
        for(let i=0;i<attacker.length && i<healer.length;i++)
        {
            if(attacker[i].pos.roomName != healer[i].pos.roomName)
            {
                const pa = PositionHelper.ToWorld( attacker[i].pos);
                const ph = PositionHelper.ToWorld( healer[i].pos);
                sum_x +=  pa.x-ph.x;
                sum_y += pa.y-ph.y;
            }
            else
            {
 
                sum_x +=  attacker[i].pos.x-healer[i].pos.x;
                sum_y += attacker[i].pos.y-healer[i].pos.y;
            }

        }
        const dir = {x:sum_x/attacker.length,y:sum_y/attacker.length};
        if(dir.x !=0)
        {
            dir.x = dir.x/Math.abs(dir.x);
        }
        if(dir.y !=0)
        {
            dir.y = dir.y/Math.abs(dir.y);
        }
        return dir;
    }
 
    /**
     * 旋转移动
     * @param radians 
     */
    public rotate(radians:number)
    {
        
        const poss = this._Formation.rotate(radians);
        this.log("info",JSON.stringify(this.getDirection()),JSON.stringify(this.creeps.map(e=>e.pos)),"\r\n旋转",radians,"旋转后的坐标",JSON.stringify(poss));
        const directions:DirectionConstant[]=[];
        for( let i=0;i<poss.length;i++)
        {
            const pos = this.creeps[i].pos;
            directions.push(PositionHelper.getDirection(pos,poss[i]));
        }
        this.move(directions);
      
    }
    /**
     * 长蛇阵移动
     * @param dir 
     */
    protected lineMove(dir: DirectionConstant )
    {
        const creeps = this.creeps;
        const dirs:DirectionConstant[]=[dir];
        const nextleaderpos =  creeps[0].pos.directionToPos(dir);
        if(nextleaderpos && creeps[1])
        {
            if(nextleaderpos.isEqualTo(creeps[1].pos))
            {
                // 当leader的方向撞到本小队的下一个成员了
                let lastDir :DirectionConstant= dir;
                for(let i=1;i<creeps.length-1;i++)
                {
                    lastDir=creeps[i].pos.getDirectionTo(creeps[i+1].pos);
                    dirs.push(lastDir);
                }
                dirs.push(lastDir);
                return this.move(dirs);
            }
        }
        for(let i=0;i<creeps.length-1;i++)
        {
            dirs.push(creeps[i+1].pos.getDirectionTo(creeps[i].pos));
        }
        return this.move(dirs);
    }

    /**
     * 方阵移动
     * @param dir 
     */
    protected sqareMove(dir:  DirectionConstant )
    {
        const next_dirs = new Array<DirectionConstant>(this.creeps.length).fill(dir);
        return this.move(next_dirs);
    }
     /**
      * 阵型移动
      * @param arg 
      */
    public move(directions:(0 | DirectionConstant)[])
    {
      
        //this.log("warn",'小队移动',JSON.stringify(directions))
        const creeps = this.creeps;
        let flag = false;
        let flag2 = true;
        for(let i=0;i<creeps.length;i++)
        {
            const code = TeamUtils.isCreepMoveable(creeps[i],directions[i]);
            if(code)
            {
                creeps[i].say(`X ${MoveTips[directions[i] as DirectionConstant]}`);
                if(code == ERR_NOT_FOUND)
                {
                    flag = true;
                }
                flag2 =  false;
            }
        }
        // 当小队里有成员同时在过道两侧时,则不进行出口判断
        if(flag2 == false)
        {
            if(flag)
            {
                // 存在经过出口的情况
                if( !creeps.some((e,index)=>
                {
                    const p = UtilsHelper.GetDirectionPos(e.pos,directions[index]);
                    return PositionHelper.isInExit(p)&&  creeps.some(e=>e.pos.isEqualTo(p));
                }))
                {
                    // 不存在两个爬以上夹在出口
                    creeps.forEach(e=>e.move(0 as DirectionConstant));
                    return false;
                }
            }
            else 
            {
                creeps.forEach(e=>e.move(0 as DirectionConstant))
                return false;
            }
        }
       
        
        
       //  global.LogDebug(`下一次移动指令:${JSON.stringify(directions)}`);
        for(let i=0;i<directions.length;i++)
        {
            if(directions[i])
            {
                if(!creeps[i])
                {
                    continue;
                }
                // creeps[i].pos.directionToPos(directions[i] as DirectionConstant)?.lookFor(LOOK_CREEPS).forEach(e=>e.my && !combatRoles.has(e.ActiveRole()) && avoidAnyMove(e,true)) ;
                // const frontCreep = creeps[i].pos.directionToPos(directions[i] as DirectionConstant)?.lookMyCreep();
                // if(frontCreep && frontCreep.my && !combatRoles.has(frontCreep.ActiveRole()) )
                // {
                //     avoidAnyMove(frontCreep,true)
                // }
               
                creeps[i].move(directions[i] as DirectionConstant );
                creeps[i]._say(MoveTips[directions[i] as DirectionConstant])
            }
            else 
            {
                this.log("error",'小队移动失败 无法移动',directions[i])
            }
        }
        // 注册下一帧预定坐标,当小队之间的成员互换位置时，这时如果寻路就会出现自己被自己阻挡导致不能寻路的bug.. 暂时注释
        // this.registerNextBlock(directions);
        return true;
    }
    public teamMove()
    {
        if(this.path?.NextDirections)
        {
            if(this.move(this.path?.NextDirections))
            {
                delete this.path.NextDirections;
                this.path.index++;
            }
        }
        return true
    }
     
    /**
     * 靠近
     * @param targetOffset 
     *  @param isrush = true 忽视算伤
     */
    public moveClose(targetOffset:IFVector2,isrush = false):boolean
    {
        this.updateRandomIndex();
        const team = this;
         if(TeamUtils.isNearTarget(targetOffset))
         {
             // 已经贴脸了。不能往前移动了
             // team.log("info",`不能移动了`);
             return false;
         }
         const move_dirs =this.getMoveDirections(targetOffset,3);
         global.Log.Info(`${this.GUID()} ${JSON.stringify(targetOffset)} 可选指令 ${JSON.stringify(move_dirs)}`);
         for(const e of move_dirs)
         {
           // global.Log.Info(`moveClose 可选移动指令:${e}`);
            const code = TeamUtils.isSqareMoveable(team,e);
            if(code)
             {
                let bval = code ==1?true:false;
                if(isrush)
                {
                    team.moveByDirection(e);
                    return true;
                }
                else
                {
                    if(TeamMoveUtils.getDangerousFactor(team,e,team.roomName,bval)<1.15)
                    {
                        team.moveByDirection(e);
                        // const next_dirs = new Array<DirectionConstant>(team.creeps.length).fill(e);
                        // const ret = team.move(next_dirs);
                        // global.LogDebug(`贴近  move_dirs:${JSON.stringify(move_dirs)}  最终方向:${e}`);
                        return true;

                    }
                }
                
             }
         }
         return false;
    }

    /**
     * 原地不动
     * @param targetVec 
     */
    public standard(targetVec:IFVector2):boolean
    {
         const team = this;

        const hostfile =TeamMoveUtils.getHostileField(team);
        if(Math.abs(targetVec.x)>1 && Math.abs(targetVec.y)>1&&Math.abs(hostfile.x)>1 && Math.abs(hostfile.y)>1 )
        {
            return false;
        }
         const team_dir:IFVector2=team.getDirection();
         const angle = Math2D.angle(team_dir,targetVec);
         if(angle>Math.PI/4)
         {
             //
             let rotate_ = 0;
             if(Math2D.cross(team_dir,targetVec)>0)
             {
                 rotate_ = angle;
             }
             else
             {
                 rotate_ = Math.PI*2- angle;
             }
           
             rotate_ =  Math.round(rotate_/(Math.PI/2))*Math.PI/2;
             team.log("info","方向",JSON.stringify(team_dir),"目标",JSON.stringify(targetVec),"\r\n","夹角",rotate_)
             if(team.isInSameroom() && rotate_>0 && rotate_<Math.PI*2)
             {
                // 弧度
                team.rotate(rotate_);
               // global.LogDebug(` 原地攻击 ${rotate_}`);
                return true;
             }

         }
         return false;
    }

    /**
     * 逃跑
     * @param targetVec 
     */
    public moveFlee(targetVec:IFVector2):boolean
    {
        const team = this;
        let bval = false;
        if(TeamMoveUtils.isMoveToSWAMP(team,0 as DirectionConstant,team.roomName))
        {
            bval = true;
        }
        // this.log('info','跑路')
        if(!this.isToughWillbeBroken()&& TeamMoveUtils.getDangerousFactor(team ,0,team.roomName,bval)<0.8 )
        {
            return false
        }
        const hostfile = TeamMoveUtils.getHostileField(team);
        if((hostfile.x+hostfile.y)==0)
        {
            this.log('info',JSON.stringify(hostfile),'敌方单位没有攻击性不逃跑',)
            return false;
        }
            // team.visualEnemyField(hostfile);
        const flee_dirs = this.getMoveDirections(hostfile);
        const sort_dirs=(dirs:DirectionConstant[])=>{
            const weight:Record<DirectionConstant,number>= {} as any;
            for(let i=0;i<dirs.length;i++)
            {
                weight[dirs[i]]=(i+1)/dirs.length;
            }
            return _.sortBy(dirs,e=>weight[e]+(TeamMoveUtils.isMoveToSWAMP(team,e,team.roomName)?1:0));
        }
        const dirs_after_sort = sort_dirs(flee_dirs);
        let moveabledir;
        for(const e of dirs_after_sort)
        {

            const code = TeamUtils.isSqareMoveable(team,e);
            if(code)
             {
                let bval = code ==1?true:false;
                if(!moveabledir)
                {
                    moveabledir = e;
                }
                if(TeamMoveUtils.getDangerousFactor(team ,e,team.roomName,bval)<=1 )
                {
                    const ret =team.moveByDirection(e)
                    // const next_dirs = new Array<DirectionConstant>(team.creeps.length).fill(e);
                    // const ret = team.move(next_dirs);
                    this.log("info",`move_dirs:${JSON.stringify(flee_dirs)}  最终逃跑方向:${e} ${ret}`);
                    return true;
                }
            }
        }
        // 无处可逃就随便挑一个方向逃吧
        if(moveabledir)
        {
            const next_dirs = new Array<DirectionConstant>(team.creeps.length).fill(moveabledir);
            const ret = team.move(next_dirs);
        }  
        this.log("warn",`move_dirs:${JSON.stringify(flee_dirs)} 无处可逃`);
        return true;
    }

    /**
     * 移动集合
     * @param leadpos 队长的目标位置
     */
    public moveAssemble(leadpos:RoomPosition)
    {
        
        const poss =TeamUtils.ArmyPositions(leadpos,this._Formation.getSlots());

        for(let i=0;i<this.creeps.length;i++)
        {
            // this.creeps[i].moveTo(PositionHelper.Create({roomName:this.roomName,x:poss[i].x,y:poss[i].y}));
            if(this.creeps[i].isSpawned())
            {
                this.creeps[i].mymoveTo({pos:PositionHelper.Create({roomName:this.roomName,x:poss[i].x,y:poss[i].y}),range:0},{}); 
            }
            
        }

         
    }

    public findAssemble(start:RoomPosition)
    {
        // 从当前坐标查找集合点
        const poss = TeamUtils.findAssemble(start,this._Formation.getSlots());
        if(poss)
        {
            return poss;
        }
        this.log("error",`找不到集合点`,JSON.stringify(start),JSON.stringify(this._Formation.getSlots()))
        throw new Error(`  找不到集合点 `);
    }
    /**
     * *************************************************************************************
     * 战斗相关
    */
   
    public attack(targets:string[])
    {
        const attacker = this.getAttacker();
        if(attacker.length>0)
        {
            for(const atk of attacker)
            {
                let f = true;
                if(atk.memory.body[RANGED_ATTACK])
                {
                    f=false;
                    RangeAttackStrategy.attack(this,targets);
                } 
                if(atk.memory.body[WORK])
                {
                    return DismantleStrategy.attack(this,targets);
                }
                else  if(atk.memory.body[ATTACK])
                {
                    return AttackStrategy.attack(this,targets);
                } 
                else
                {
                    if(f)
                    {
                        this.log("error","小队剩余成员无法攻击");
                    }
                }
            }
            
        }

    }
    
    public  getHurtCreep()
    {
        const creeps:Creep[]=[];
        for(const item of this.creeps)
        {
            if(  item.hits<item.hitsMax)
            {
                creeps.push(item);
            }
        }
        return creeps;
    }
    /**
     * 
     * 获取小队的最大治疗量
     */

    @cache_return("cache_heal",0)
    public getTeamHealMax()
    {
        let sum = 0;
        for(const e of this.creeps)
        {
            sum +=e.getAbilityHeal();
        }
        return sum;
    }
    public healTeam()
    {
        const hurtcreep  = this.getHurtCreep();
        const healer = this.creeps.filter(e=>e.body && e.memory.body[HEAL]);
        // const attacker = this.getAttacker();
        const _this = this;
        this._healTeam(hurtcreep,healer,()=>{
            return _this.getAttacker();
        });
    }

    public healAroundCreep()
    {
        const hurtcreeps  = this.getHealer().map(e=>e.room.getHurtCreeps().filter(c=>c.pos.getRangeTo(e)<=3));
        const hurtcreep =  _.flatten(hurtcreeps) 
        const healer = this.creeps.filter(e=>e.body && e.memory.body[HEAL]);
        // const attacker = this.getAttacker();
        const _this = this;
        this._healTeam(hurtcreep,healer,()=>{
            return _this.getAttacker();
        });
    }
    /**
     *
     * @param hurtcreep 受伤单位
     * @param allheals 有治疗部件的单位
     * @param attackers 前排单位
     * @param leftbeheal 如果有多余的治疗则治疗谁
     */
    protected _healTeam(hurtcreep:Creep[],allheals:Creep[],leftbehealgetter:ICreepGetter)
    {
        if(hurtcreep.length>0)
        {
           let lefthealrs = this.healTeamHurt(hurtcreep,allheals);
           if(lefthealrs.length>0)
           {
                // lefthealrs =  _.sortBy(lefthealrs,e=>-e.getAbilltyHeal());
                const leftbeheal=leftbehealgetter();
                const behurt = _.min(leftbeheal,e=>e.hits);  // 敌方最喜欢打的单位
                for(const e of lefthealrs)
                {
                    e.heal(behurt);
                }
           }

        }
        else
        {
            const leftbeheal=leftbehealgetter();
           // 全都满血随便治疗
            for(let i=0;i<allheals.length;i++)
            {
                const ihurstcreepindex = i%leftbeheal.length;
                allheals[i].heal(leftbeheal[ihurstcreepindex]);
            }

        }
    }
    /**
     *
     * @param hurtCreep 受伤的爬
     * @param healer 治疗爬
     * @returns 返回剩余的治疗爬
     */
    protected healTeamHurt(hurtCreep:Creep[],healer:Creep[])
    {
        const hurtcreeps =  _.map(hurtCreep,e=>{return {
            creep:e,
            tmphit:e.hits
        }})
        while(hurtcreeps.length>0 && healer.length>0)
        {
            const beheal = _.max(hurtcreeps,e=>
                (e.creep.hitsMax-e.tmphit)*
                (e.creep.bodyCount(HEAL)-e.creep.getActiveBodyparts(HEAL)+1)
                );
            const afetrhits = this.healCreep(beheal.creep,beheal.tmphit,healer);
            beheal.tmphit= afetrhits;
            if(afetrhits>=beheal.creep.hitsMax)
            {
                const index = hurtcreeps.findIndex(e=>e.creep.name == beheal.creep.name);
                if(index>=0)
                {
                    hurtcreeps.splice(index,1);
                }
                else
                {
                    // 错误
                }
            }
        }
        return healer;
    }

    // 治疗爬
    /**
     * @return 治疗后的hits
     * @param hurtCreep 受伤的爬
     * @param tmphit 缓存值爬的hit
     * @param healer 治疗爬
     */
    private healCreep(hurtCreep:Creep,tmphit:number,healer:Creep[]):number
    {
        const heal_Neeed = hurtCreep.hitsMax-tmphit;    // 需要的治疗量

        const besthealer = _.min(healer,e=>Math.abs(e.getAbilityHeal()-heal_Neeed));
        besthealer.heal(hurtCreep);
       //  Memory.Debug[`${Game.time}_${global.uniqueid()}heal ${besthealer.name}`] = hurtCreep.name;
        const index = healer.findIndex(e=>e.name == besthealer.name);
        healer.splice(index,1);
        return besthealer.getAbilityHeal()+tmphit;
    }
    /**
     * ***************************************************************************************
     * 算伤相关
    */
    
   /**
    * *******************************************************************************************
   */
    /*************************************************************************************************/

    // 属性判断
    /*---------------------------------------------------------------------------------*/
    public isInSameroom()
    {
        const rooms = new Set<string>()
        for(const e of this.creeps )
        {
            rooms.add(e.pos.roomName);
        }
        return rooms.size ==1;
    }

    /**
      * 获取在这个方向的可选移动方向
      * @param targetDir
      * @returns
      */
     protected getMoveDirections(targetDir:IFVector2,length?:number):DirectionConstant[]
     {
         // 1.获取角度
         let rotate_ = Math2D.angleZ(targetDir,{x:1,y:0});
         global.Log.Info(`${JSON.stringify(targetDir)} ${rotate_}`);
         let angle_index = Math.round(rotate_/ 22.5);
         const dir =  angleIndex(angle_index%16);
        // 需要重新排序，根据是否存在沼泽
        if(length)
        {
            const randomdir =  movedirection[dir][this._move_clonse_random_moveIndex];
            const rets =  _.clone(movedirection[dir]).splice(0,length) ;
            rets.push(randomdir);
            return rets;
        }
        else
        {
            return  _.clone(movedirection[dir])
        }
    }
    /**
     * 随机移动索引
     */
    private updateRandomIndex()
    {
        if(Game.time%15==0)
        {
            if(Math.round(Math.random()*10)%2==0)
            {
                this._move_clonse_random_moveIndex = 3
            }
            else
            {
                this._move_clonse_random_moveIndex = 4
            }

        }
    }
    /**
     * 护甲是否被打穿了
     * @returns 
     */
    public isToughWillbeBroken()
    {
        for(const e of this.creeps )
        {
            if(e && e.memory.BoostLevel &&  e?.getActiveBodyparts(TOUGH)<=3)
            {
                return true;
            }
        }
        return false;
    }
 
    /**
     * 判断目标位置是否可移动。同时将阻挡移动的爬添加到阻挡列表
     * @param checkPos 
     * @returns 
     */
    public isPositionMoveable(checkPos:RoomPosition)
    {
        if(Game.rooms[checkPos.roomName] &&Game.rooms[checkPos.roomName].getTerrain().get(checkPos.x,checkPos.y) == TERRAIN_MASK_WALL)
        {
            return false;
        }
        const blockstructure = TeamUtils.findBlockStructure(checkPos);
        if(blockstructure.length>0)
        {
            return false;
        }
        return true
         
    }
    private registerNextBlock(directions:(0 | DirectionConstant)[])
    {
        const creeps = this.creeps;
        for(let i=0;i<creeps.length;i++)
        {
            const creep =creeps[i];
            if(creep&& directions[i])
            {
                const p = creep.pos.directionToPos(directions[i] as DirectionConstant);
                if(p)
                {
                    creep.room.registerBlocks([p]);
                }
            }
        }
    }

    public getNextPositions()
    {
        const nodeMemory = this.getNodeMemory();
        if(nodeMemory.path && nodeMemory.path!.path[nodeMemory.path!.index+1]) 
        {
            const dir =parseInt( nodeMemory.path!.path[nodeMemory.path!.index+1]) as DirectionConstant;
            if(dir)
            {
                const poss = _.map(this.creeps,e=>e.pos);
                let nextTeamPos =   _.map(poss,e=> UtilsHelper.GetDirectionPos(e,dir));
                return nextTeamPos;
            }
            
        }
        return undefined;
    }
    /*--------------------------------------------------------------------------------------*/
}